/**
 * @author Kevin Gomes
 */

import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.UUID;

import utils.*; //utils written for this project. Has MysqlConnect.java

/**
 * Class: PServer
 * 
 * Handles the server functionality of a Peer.
 */
public class PServer {
    /**
     * Peer IP Address.
     */
    private String peer_ip;
    
    /**
     * DB Connection.
     */
    private MysqlConnect conn;
    
    /**
     * Array of Socket objects. This is used to store the client socket connections.
     */
    private Socket clientSockets[];

    /**
     * Server Socket instance
     */
    private ServerSocket serverSocket;

    /**
     * Stores all the descriptor IDs (Query & Query Hit) this server has seen.
     */
    private String descriptorIds[];

    /**
     * Constructor.
     */
    public PServer() { }

    /**
     * Does all the initializing activities for the server.
     */
    public void init() {
	//Save peer ip address
        this.peer_ip = this.getIp();

	//Setup a database connection	
	this.conn = new MysqlConnect();

	this.createSocket();
    }

    /**
     * Creates a server socket to which other peer clients can connect to.
     */
    public void createSocket() throws IOException {
	try {
	    this.serverSocket = new ServerSocket(4444,20,this.peer_ip);

	    while(true) {
		Socket clientSocket = this.serverSocket.accept();
		
		//Integer count = this.clientSockets.length;
		String key = clientSocket.getInetAddress().getHostAddress();
		this.clientSockets[key] = clientSocket;
		
		ServerThread thread = new ServerThread(clientSocket, this);
		thread.start();
	    }
	} catch (IOException e) {
	    e.printStackTrace();
	    System.exit(-1);
	}
    }

    /**
     * Returns the IP Address of the machine this client is running on.
     */
    public String getIp() {
        String ip=new String ();
        try{
            InetAddress ownIP = InetAddress.getLocalHost();
            ip = ownIP.getHostAddress();
        }catch (Exception e){
            System.out.println("Exception caught ="+e.getMessage());
        }
        return ip;
    }

    /**
     * Searches for a file name and returns whether it has the file or not.
     */
    public Boolean search(String fileName) {
	Boolean isFile = this.conn.checkPeerFile(this.peer_ip,fileName);
	return isFile;
    }

    /**
     * Returns the QueryHit descriptor.
     * 5acfdc70-8aa7-4b6e-9a3e-14f2e835d0ae;129;3;0;8"+"2;4444;192.168.1.1;0;Fileindex;filesize;filename;NULL
     */
    public String createQueryHitDescriptor(String ttl, String fileIndex, String filesize, String filename) {
	UUID val = UUID.randomUUID();
	String descriptorId = String.valueOf(val);
	String payloadDescriptor = "129";
        //String ttl = "3";
	String hop = "0";
	String payloadLength = "1";
	
	String searchCount = "1";
	String port = "4444";
	String ip = this.peer_ip;
	String speed = "0"; //Indicates max. speed

	String descriptor = descriptorId+";"+payloadDescriptor+";"+ttl+";"+hop+";"+payloadLength+";"+searchCount+";"+port+";"+ip+";"+speed+";"+fileIndex+";"+filesize+";"+filename+";NULL";

	return descriptor;
    }

    /**
     * 
     */
    public String fetchDescriptorId(String descriptor) {
	String tokens[] = descriptor.split(",");
	return tokens[0];
    }

    /**
     *
     */
    public void processQuery(String descriptor, String remoteIp) {
	//Accept Query descriptors
	//Store the descriptor ID
	//Forward the descriptor to the Client so that it can be sent to the neighbors.

	String tokens[] = descriptor.split(",");
	String descriptorId = tokens[0];
	String payloadDescriptor = tokens[1];
	int ttl = new Integer(tokens[2]);
	int hop = new Integer(tokens[3]);

	if(this.descriptorIds[descriptorId] != null) {
	    //Process each query only once.
	} else {
	    //Process this descriptor only if it has not been processed before.
	    this.descriptorIds[descriptorId] = remoteIp;
	    
	    //Forward Query only if TTL is not zero.
	    if(ttl != 0) {
		String newDescriptor = this.clientObj.reduceDescriptorTTL(descriptor);
		this.clientObj.talkToNeighbor(newDescriptor);
	    }
	}
    }

    /**
     *
     */
    public void processQueryHitDescriptor(String descriptor) {
	String tokens[] = descriptor.split(",");
	String descriptorId = tokens[0];
	String payloadDescriptor = tokens[1];
	int ttl = new Integer(tokens[2]);
	int hop = new Integer(tokens[3]);

	String remoteIp = this.descriptorIds[descriptorId];
	if(remoteIp != null) {
	    //Forward Query only if TTL is not zero.
	    if(ttl != 0) {
		String newDescriptor = this.clientObj.reduceDescriptorTTL(descriptor);
		Socket clSocket = this.clientSockets[remoteIp];
		

		//TODO: Send the newescriptor to the remote client.
	    }
	}
    }
    
    public static void main(String[] args) {
	if(args.length !=1 ) {
	    System.out.println("Syntax: java PServer <filename_to_search>");
	    System.exit(1);
	}

	PServer obj = new PServer();
	obj.init();

        Boolean isFile = obj.search(args[0]);
	System.out.println(isFile);
    }
}